package com.aldobucchi.x.flash.geom
{
	
	import flash.geom.Matrix;
	import flash.geom.Point;
	
	import com.aldobucchi.x.Math.NormalizedFactor;
	
	
	public class WarpPath
	{
	
		
		
		private var startTransform:Matrix;
		
		private var invertedStartTransform:Matrix;


		private var endTransform:Matrix;
		
		private var invertedEndTransform:Matrix;

		
		
		
		private var anchorInStartSpace:Point;
		
		
		
		
		private var start:Transformation2D;

		private var end:Transformation2D;



		internal var absoluteStartAnchor:Point;
		
		internal var absoluteEndAnchor:Point;


		
		internal var scaleFactor:NormalizedFactor;

		internal var rotationDelta:Number;





		/**
		 * 
		 * @param startTransform
		 * 
		 * 
		 * @param anchor
		 * 			The anchor ( point that must move in straight line ) in the absolute coordinate space
		 * 
		 * @param endTransform
		 * 
		 * 
		 */
		public function WarpPath( startTransform:Matrix, anchor:Point, endTransform:Matrix )
		{

			
			this.startTransform = startTransform;
			
			invertedStartTransform = startTransform.clone( );
			invertedStartTransform.invert( );


			this.endTransform = endTransform;
			
			invertedEndTransform = endTransform.clone( );
			invertedEndTransform .invert( );



			////////////////////////////////
			// where is the anchor in the start coordinate space?
			////////////////////////////////

			anchorInStartSpace = invertedStartTransform.transformPoint( anchor );




			////////////////////////////////
			// decompose to transformations
			////////////////////////////////

			start	= Transformation2D.approximateFromRegularMatrix( startTransform );
			end	 	= Transformation2D.approximateFromRegularMatrix( endTransform );			
			
			
			trace( "warp: " + start + " --> " + end );
			
			
			//////////////////////////////
			// calculate deltas
			//////////////////////////////
			
			scaleFactor 	= new NormalizedFactor( end.scaleX / start.scaleX );
			rotationDelta 	= end.rotationRadians - start.rotationRadians;
			
			
			
			
			//////////////////////////////
			// anchor points
			//////////////////////////////
			
			absoluteStartAnchor = anchor;
			absoluteEndAnchor 	= endTransform.transformPoint( invertedStartTransform.transformPoint( absoluteStartAnchor ) );


			trace( "anchors: " + absoluteStartAnchor + " --> " + absoluteEndAnchor );

		}
		
		
		// funcs are internal so they can be accessed by unit tests
		
		internal function getScalingForStep( step:Number ):Number
		{
			return start.scaleX * scaleFactor.ponderate( step );
		}
		

		
		internal function getRotationForStep( step:Number ):Number
		{
			return start.rotationRadians + ( rotationDelta * step );
		}
		
		

		internal function getAnchorPositionForStep( step:Number ):Point
		{
			return Point.interpolate( absoluteEndAnchor, absoluteStartAnchor, step );
		}
		
		
		
		
		/**
		 * 
		 * returns the transformation matrix that should be applied so that
		 * 
		 * @param step
		 * 		A number from 0 to 1, representing the portion of the path
		 * 
		 * @return 
		 * 
		 */		
		public function getTransformationForStep( step:Number ):Transformation2D
		{

			// each step has a given scaling and rotation
			var rotation		:Number = getRotationForStep( step );
			var scale			:Number = getScalingForStep( step );

			// where should the anchor be at this fraction of the path?
			var stepAnchor		:Point = getAnchorPositionForStep( step );


			// we can now create the partial transformation to predict where the anchor would be
			// if we applied no translation
			var inversePartialTransform:Matrix = new Matrix( );
			inversePartialTransform.scale( scale, scale );
			inversePartialTransform.rotate( rotation );
			inversePartialTransform.invert( );
			var untranslatedAnchor:Point = inversePartialTransform.transformPoint( anchorInStartSpace );

			// calculate necessary translation
			var trans:Point = new Point( 
					stepAnchor.x - untranslatedAnchor.x ,
					stepAnchor.y - untranslatedAnchor.y
				);


//			var newOrigin:Point = GeomUtil.getTranslation( 
//										rotation, 
//										scale, 
//										invertedStartTransform.transformPoint( absoluteStartAnchor ), 
//										invertedStartTransform.transformPoint( stepAnchor ) 
//										);
//
//
//			newOrigin = startTransform.transformPoint( newOrigin );
			

			return new Transformation2D( trans.x, trans.y, scale, scale, rotation );

		}
		
		

	}
	
}